Skip to content

glibc-compat: add static-link mmap shim (32-bit off_t for vendor V2 blobs)#2110

Merged
widgetii merged 1 commit into
masterfrom
fix/hi3520dv200-glibc-compat-mmap-shim
May 18, 2026
Merged

glibc-compat: add static-link mmap shim (32-bit off_t for vendor V2 blobs)#2110
widgetii merged 1 commit into
masterfrom
fix/hi3520dv200-glibc-compat-mmap-shim

Conversation

@widgetii
Copy link
Copy Markdown
Member

Summary

Mirror of #2000 but for glibc vendor binaries (V2 SoCs like hi3520dv200).

Vendor glibc binaries from the V2 era (`libmpi.so` etc.) were built without `_FILE_OFFSET_BITS=64` — their `mmap()` import takes a 32-bit `off_t`. musl's `mmap()` exports 64-bit `off_t`. When libmpi dynamic-links against musl, the high 32 bits of the offset come from uninitialised stack; the kernel sees a garbage pgoff and rejects with `EINVAL`.

Symptom on hi3520dv200: every `HI_MPI_VENC_CreateChn` returns `0xa007800c` (`EN_ERR_VENC_NOMEM`) because libmpi can't mmap the model_buf via `/dev/venc`. Confirmed via an `LD_PRELOAD` trace shim that wraps `mmap()`:

```
mmap(fd=28[/dev/venc], off=0x402b65d8, len=229376) = -1 errno=22 EINVAL
mmap err,page addr:-1896943616 u32PagePhy size:114688
VENC: CreateChn(0) 0xa007800c
```

`0x402b65d8` is a userspace VA (lower 12 bits constant `0x5d8`, upper bits vary between runs with ASLR) — pure stack garbage. The vendor's printed "page addr / u32PagePhy size" values are libmpi-internal state, not the real mmap args, so the message is misleading.

Fix

Mirror PR #2000's pattern, scoped to glibc vendor blobs:

  • `glibc-compat/src/glibc-compat-static.c`: new file, `mmap()` / `mmap64()` wrappers that take `uint32_t offset` and go straight to `SYS_mmap2` with `offset >> 12` as pgoff, bypassing musl's libc wrapper entirely.
  • `glibc-compat/src/Makefile`: build both `libglibc-compat.so` (the existing `__xstat`/`__isoc99_sscanf` shim) and the new `libglibc-compat-static.a`.
  • `glibc-compat/glibc-compat.mk`: `GLIBC_COMPAT_INSTALL_STAGING = YES` + `INSTALL_STAGING_CMDS` so dependent packages can link `-lglibc-compat-static`.
  • `Makefile` (`BUNDLE_SDK`): produce `libglibc-compat.so` and `libglibc-compat-static.a` in the published toolchain SDK tarball next to the existing uclibc-compat ones.

The wrapper must be statically linked into the consumer executable. Putting it in a shared library would override musl's mmap process-wide and break musl's own internal callers (malloc, dlopen, …) — that's exactly the bug PR #2000 fixed for uclibc-compat.

Why static linking works

The dynamic linker resolves an undefined import like `mmap` from libmpi.so by walking the global symbol scope: the executable first, then `DT_NEEDED` libraries in order. With `-Wl,--export-dynamic-symbol=mmap` on the executable (or just having the symbol from a static lib that gets pulled in via reference), the executable's `mmap` enters its `.dynsym` and libmpi binds against it instead of musl. musl's own internal mmap calls still bind locally because musl uses internal versions / direct syscalls and isn't subject to symbol interposition for its own callers.

Test plan

  • `make BOARD=hi3520dv200_lite` builds clean.
  • `output-hi3520dv200/per-package/glibc-compat/host//sysroot/usr/lib/libglibc-compat-static.a` exists (staging install works).
  • Local test: consumer app (the dvr_home demo at `~/hifb-demo`) with the mmap shim statically linked + `-Wl,--export-dynamic-symbol=mmap` makes `HI_MPI_VENC_CreateChn` succeed on all 4 channels. Trace shim now shows the syscall reaching the kernel with a valid pgoff and returning a valid mapping.
  • CI: SDK build matrix for hi3520dv200_lite (will be wired in a follow-up — currently absent because hi3520dv200 had no opensdk wiring until hisilicon-opensdk: wire hi3520dv200 (replace 4 vendor blobs with source-built) #2109).
  • Cross-platform regression check: cv100/ev200/cv500 unaffected (BUNDLE_SDK now also writes libglibc-compat.{so,a} but those families don't link against it).

Refs: #1992 (toolchain ABI audit), #1993 (cv100 stat shim), #2000 (cv100 static-link split), #2109 (hi3520dv200 opensdk wiring that built on top of glibc-compat).

Vendor glibc binaries from the V2 era (e.g. hi3520dv200's libmpi.so)
were built without _FILE_OFFSET_BITS=64 so their mmap() takes a 32-bit
off_t. musl's mmap() exports 64-bit off_t — when libmpi dynamic-links
against musl on a modern rootfs, the high 32 bits of the offset arg
come from uninitialised stack and the kernel sees a garbage pgoff,
rejecting with EINVAL.

Symptom on hi3520dv200: every HI_MPI_VENC_CreateChn returns 0xa007800c
(EN_ERR_VENC_NOMEM) because libmpi can't mmap the model_buf via
/dev/venc. Confirmed via LD_PRELOAD trace shim that wraps mmap():
the syscall reaches the kernel with off=0x402b65d8 — a userspace VA
(varies between runs with ASLR), clearly stack garbage.

Fix: add glibc-compat-static.c with a 32-bit off_t mmap()/mmap64()
wrapper that goes straight to SYS_mmap2 bypassing musl's libc wrapper.
Same pattern as #2000 (uclibc-compat-static for hi3516cv100). The
function must be statically linked into the consumer executable (not
in a .so) so the dynamic linker resolves vendor .so imports of mmap
to the executable's symbol table BEFORE musl — putting it in a .so
would override musl process-wide and break musl's own internal mmap
callers (malloc, dlopen, etc.).

- glibc-compat/src/glibc-compat-static.c: new file, mmap()/mmap64()
  wrappers calling SYS_mmap2 with pgoff
- glibc-compat/src/Makefile: build both libglibc-compat.so and
  libglibc-compat-static.a
- glibc-compat/glibc-compat.mk: INSTALL_STAGING=YES, install .a to
  STAGING_DIR so dependent packages can link -lglibc-compat-static
- Makefile (BUNDLE_SDK): produce libglibc-compat.so and
  libglibc-compat-static.a in the published toolchain SDK tarball,
  mirroring the existing uclibc-compat handling

Verified on lab DVR (openipc-hi3520dv200.dlab.torturelabs.com):
linking dvr_home with the mmap shim makes HI_MPI_VENC_CreateChn
succeed on all 4 channels.

Refs: #1992 (toolchain ABI audit), #1993 (cv100 stat shim),
      #2000 (cv100 static-link split)
@widgetii widgetii force-pushed the fix/hi3520dv200-glibc-compat-mmap-shim branch from 8f8363c to 028db19 Compare May 18, 2026 10:18
@widgetii widgetii merged commit b9d5883 into master May 18, 2026
96 checks passed
@widgetii widgetii deleted the fix/hi3520dv200-glibc-compat-mmap-shim branch May 18, 2026 11:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant